using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using Magiq.Support;
using Magiq.Update;

namespace Magiq.Databases.Update
{
    public class TableUpdate<T>
    {
        private readonly LambdaExpression where;
        private readonly string whereParameter;
        private readonly IQueryable<T> whereQuery;
        private bool? isWhereInvalidator;

        public TableUpdate(IQueryable<T> whereQuery)
        {
            this.whereQuery = whereQuery;
            where = whereQuery.Expression as LambdaExpression;

            if (where == null)
            {
                var memberCall = whereQuery.Expression as MethodCallExpression;

                if (memberCall != null && memberCall.Arguments.Count == 2)
                {
                    var unary = memberCall.Arguments[1] as UnaryExpression;
                    if (unary != null)
                        where = unary.Operand as LambdaExpression;
                }

                if (where == null)
                    throw new NotSupportedException("I don't know how to get the lambda expression from " +
                                                    whereQuery.Expression);
            }

            whereParameter = where.Parameters.Single().Name;
            PropertySets = new List<IPropertySet>();
        }

        public bool IsWhereInvalidation
        {
            get
            {
                if (!isWhereInvalidator.HasValue)
                    isWhereInvalidator = PropertySets.Any(IsWhereInvalidating);
                return isWhereInvalidator.Value;
            }
        }

        public List<IPropertySet> PropertySets { get; private set; }

        public IQueryable<T> Where
        {
            get { return whereQuery; }
        }

        public void Set(IPropertySet set)
        {
            PropertySets.Add(set);
        }

        private bool IsWhereInvalidating(IPropertySet set)
        {
            var propertyParameter = where.Parameters.Single().Name;
            var stringToFind = set.PropertyExpression.ToString()
                .GetFrom("=>")
                .Replace(propertyParameter + ".", whereParameter + ".").Trim();

            return where.ToString().Contains(stringToFind);
        }
    }
}